扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国IT实验室 来源:中国IT实验室 2007年9月30日
关键字:
在本页阅读全文(共2页)
用闭包进行定制
您已经知道如何使用现成的闭包。Ruby 让您也可以编写使用自己的闭包的方法。这种自由的形式意味着 Ruby API 的代码会更加紧凑,因为 Ruby 不需要在代码中定义每个使用模型。您可以根据需要通过闭包构建自己的抽象概念。例如,Ruby 的迭代器数量有限,但该语言没有迭代器也运行得很好,这是因为可以通过闭包在代码中构建您自己的迭代概念。
要构建一个使用闭包的函数,只需要使用 yield
关键字来调用该闭包。清单 6 是一个例子。paragraph
函数提供第一句和最后一句输出。用户可以用闭包提供额外的输出。
清单 6. 构建带有闭包的方法
def paragraph puts "A good paragraph should have a topic sentence." yield puts "This generic paragraph has a topic, body, and conclusion." end paragraph {puts "This is the body of the paragraph."} Results: A good paragraph should have a topic sentence. This is the body of the paragraph. This generic paragraph has a topic, body, and conclusion. |
优点
通过将参数列表附加给 yield
,很容易利用定制闭包中的参数,如清单 7 中所示。
清单 7. 附加参数列表
def paragraph topic = "A good paragraph should have a topic sentence, a body, and a conclusion. " conclusion = "This generic paragraph has all three parts." puts topic yield(topic, conclusion) puts conclusion end t = "" c = "" paragraph do |topic, conclusion| puts "This is the body of the paragraph. " t = topic c = conclusion end puts "The topic sentence was: '#{t}'" puts "The conclusion was: '#{c}'" |
不过,请认真操作以保证得到正确的作用域。在闭包里声明的参数的作用域是局部的。例如,清单 7 中的代码可以运行,但清单 8 中的则不行,原因是 topic
和 conclusion
变量都是局部变量:
清单 8. 错误的作用域
def paragraph topic = "A good paragraph should have a topic sentence." conclusion = "This generic paragraph has a topic, body, and conclusion." puts topic yield(topic, conclusion) puts conclusion end my_topic = "" my_conclusion = "" paragraph do |topic, conclusion| # these are local in scope puts "This is the body of the paragraph. " my_typic = topic my_conclusion = conclusion end puts "The topic sentence was: '#{t}'" puts "The conclusion was: '#{c}'" |
闭包的应用
下面是一些常用的闭包应用:
当您可以用一种简单便利的方式构建自己的闭包时,您就找到了能带来更多新可能性的技术。重构能将可以运行的代码变成运行得更好的代码。大多数 Java 程序员都会从里到外 进行重构。他们常在方法或循环的上下文中寻找重复。有了闭包,您也可以从外到里 进行重构。
用闭包进行定制会有一些惊人之处。清单 9 是 Ruby on Rails 中的一个简短例子,清单中的闭包用于为一个 HTTP 请求编写响应代码。Rails 把一个传入请求传递给控制器,该控制器生成客户机想要的数据(从技术角度讲,控制器基于客户机在 HTTP accept
头上设置的内容来呈现结果)。如果您使用闭包的话,这个概念很好理解。
清单 9. 用闭包来呈现 HTTP 结果
@person = Person.find(id) respond_to do |wants| wants.html { render :action => @show } wants.xml { render :xml => @person.to_xml } end |
清单 9 中的代码很容易理解,您一眼就能看出这段代码是用来做什么的。如果发出请求的代码块是在请求 HTML,这段代码会执行第一个闭包;如果发出请求的代码块在请求 XML,这段代码会执行第二个闭包。您也能很容易地想象出实现的结果。wants
是一个 HTTP 请求包装程序。该代码有两个方法,即 xml
和 html
,每个都使用闭包。每个方法可以基于 accept
头的内容选择性地调用其闭包,如清单 10 所示:
清单 10. 请求的实现
def xml yield if self.accept_header == "text/xml" end def html yield if self.accept_header == "text/html" end |
濠碘€冲€归悘澶愬箖閵娾晜濮滈悽顖涚摃閹烩晠宕氶崶鈺傜暠闁诡垰鍘栫花锛勬喆椤ゅ弧濡澘妫楅悡娆撳嫉閳ь剟寮0渚€鐛撻柛婵呮缁楀矂骞庨埀顒勫嫉椤栨瑤绻嗛柟顓у灲缁辨繈鏌囬敐鍕杽閻犱降鍨藉Σ鍕嚊閹跺鈧﹦绱旈幋鐐参楅柡鍫灦閸嬫牗绂掔捄铏规闁哄嫷鍨遍崑宥夋儍閸曨剚浠樺ù锝嗗▕閳ь剚鏌ㄧ欢鐐寸▕鐎b晝顏遍柕鍡嫹